package com.tianji.learning.service.impl;

import cn.hutool.core.io.unit.DataUnit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author mxl
 * @since 2024-06-25
 */
@Service
@RequiredArgsConstructor
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    final CourseClient courseClient;
    final CatalogueClient catalogueClient;
    final LearningRecordMapper recordMapper;

    @Override
    public void addUserLesson(Long userId, List<Long> courseIds) {
        // 1.通过fein 远程调用课程服务
        List<CourseSimpleInfoDTO> cinfos = courseClient.getSimpleInfoList(courseIds);
        if(CollUtils.isEmpty(cinfos)){
            throw new BizIllegalException("课程信息不存在");
        }
        
        // 2.封装po实体类，填充过期时间
        List<LearningLesson> learningLessons = new ArrayList<>();
        for(CourseSimpleInfoDTO cinfo: cinfos){
            LearningLesson learningLesson = new LearningLesson();
            learningLesson.setUserId(userId);
            learningLesson.setCourseId(cinfo.getId());
            Integer validDuration = cinfo.getValidDuration();//单位月
            if(validDuration != null){ // null永久有效
                LocalDateTime now = LocalDateTime.now();
                learningLesson.setCreateTime(now);
                learningLesson.setExpireTime(now.plusMonths(validDuration));
            }
            learningLessons.add(learningLesson);
        }

        // 3.批量保存
        saveBatch(learningLessons);
    }

    @Override
    public PageDTO<LearningLessonVO> queryMyLession(PageQuery query) {
        // 1. 获取当前登录人
        Long user = UserContext.getUser();

        // 2. 分页查询我的课表
        Page<LearningLesson> page = this.lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .page(query.toMpPage("latest_learn_time", false));

        List<LearningLesson> records = page.getRecords();
        if(CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }
        // 3. 远程调用  章节数  课程名  章节数
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.
                getSimpleInfoList(records
                        .stream()
                        .map(LearningLesson::getCourseId)
                        .collect(Collectors.toList()));

        if(CollUtils.isEmpty(simpleInfoList)){
            throw new BizIllegalException("课程不存在");
        }
        // 4. 封装为VO
        Map<Long, CourseSimpleInfoDTO> cmap = simpleInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        List<LearningLessonVO> vos = new ArrayList<>();
        for (LearningLesson record : records) {
            LearningLessonVO vo = BeanUtils.copyBean(record, LearningLessonVO.class);
            CourseSimpleInfoDTO courseSimpleInfoDTO = cmap.get(record.getCourseId());
            if(courseSimpleInfoDTO == null){
                throw new BizIllegalException("课程不存在");
            }
            vo.setSections(courseSimpleInfoDTO.getSectionNum());
            vo.setCourseName(courseSimpleInfoDTO.getName());
            vo.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
            vos.add(vo);
        }

        // 5.返回
        return PageDTO.of(page, vos);
    }

    @Override
    public LearningLessonVO queryMyCurrentLession(PageQuery query) {
        // 1. 获取当前登录用户Id
        Long user = UserContext.getUser();
        // 2. 查询当前用户最近学习课程 按照 latest_learn_time 排序   正在学习 status = 1
        LearningLesson learningLesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING)
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();

        if(learningLesson == null){
            return null;
        }
        // 3. 远程调用课程服务
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);
        if(courseInfo == null){
            throw new BizIllegalException("课程不存在");
        }
        // 4. 查询课表中总的课程数
        Integer count = this.lambdaQuery().eq(LearningLesson::getUserId, user).count();

        // 5. 远程调用课程服务获取小结名称和小节的编号
        Long latestSectionId = learningLesson.getLatestSectionId();
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(CollUtils.singletonList(latestSectionId));

        if(CollUtils.isEmpty(cataSimpleInfoDTOS)){
            throw new BizIllegalException("小节不存在");
        }

        // 6. 封装并返回
        LearningLessonVO vo = BeanUtils.copyBean(learningLesson, LearningLessonVO.class);
        vo.setCourseName(courseInfo.getName());             // 课程名字
        vo.setCourseCoverUrl(courseInfo.getCoverUrl());    // 课程封面
        vo.setSections(courseInfo.getSectionNum());     // 总小节数目
        vo.setCourseAmount(count);  // 总报名课程数
        CataSimpleInfoDTO cataSimpleInfoDTO = cataSimpleInfoDTOS.get(0);
        vo.setLatestSectionName(cataSimpleInfoDTO.getName());       // 小节名字
        vo.setLatestSectionIndex(cataSimpleInfoDTO.getCIndex()); // 最近学习的小节序号

        return vo;
    }

    @Override
    public void deleteLession(Long courceId) {
        // 1.获取用户id
        Long user = UserContext.getUser();
        // 2.删除课表字段
        LambdaQueryWrapper<LearningLesson> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getCourseId, courceId);
        this.remove(lambdaQueryWrapper);
    }

    @Override
    public Long isLessonValid(Long courseId) {
        // 1. 获取用户id
        Long user = UserContext.getUser();
        if(user == null){
            return null; //免费试看
        }
        // 2. 查询用户是否购买该课程
        LearningLesson learningLesson = this.lambdaQuery().eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getCourseId, courseId).last("limit 1").one();

        if(learningLesson == null){
            throw new BizIllegalException("不存在该课程");
        }
        // 3. 校验课程过期时间
        if(learningLesson.getExpireTime() != null && learningLesson.getExpireTime().isBefore(LocalDateTime.now())){
             return  null;
        }
        return learningLesson.getId();
    }

    @Override
    public LearningLessonVO queryState(Long courseId) {
        // 1. 获取用户id
        Long user = UserContext.getUser();
        // 2. 查询用户是否购买该课程
        LearningLesson learningLesson = this.lambdaQuery().eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getCourseId, courseId).last("limit 1").one();

        // 3. 封装返回
        return BeanUtils.copyBean(learningLesson, LearningLessonVO.class);

    }

    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        // 1. 查询报名人数
        return this.lambdaQuery().eq(LearningLesson::getCourseId, courseId).count();
    }

    @Override
    public void createLearningPlan(LearningPlanDTO dto) {
        // 1. 获取用户信息
        Long user = UserContext.getUser();
        // 2. 查询课表
        LearningLesson lession = this.lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getCourseId, dto.getCourseId())
                .one();

        if(lession == null) {
            throw new BizIllegalException("该课程没有加入课表");
        }

        boolean update = this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq, dto.getFreq())
                .eq(LearningLesson::getId, lession.getId())
                .update();
        if(!update){
            throw new DbException("更新课程表学习计划错误");
        }

    }

    @Override
    public LearningPlanPageVO queryMyPlans(PageQuery pageQuery) {
        //1. 查询用户id
        Long user = UserContext.getUser();

        // 2. 查询积分 TODO
        // 3. 查询本周学习计划总数
        QueryWrapper<LearningLesson> lessonWrapper = new QueryWrapper<>();
        lessonWrapper.select("sum(week_freq) as total_plan");
        lessonWrapper.eq("user_id", user);
        lessonWrapper.eq("plan_status", PlanStatus.PLAN_RUNNING);
        lessonWrapper.in("status", LessonStatus.LEARNING, LessonStatus.NOT_BEGIN);
        Map<String, Object> map = this.getMap(lessonWrapper);
        Integer totolPlan = Integer.valueOf(0);
        if(map != null && map.get("total_plan")!=null){
            totolPlan = Integer.valueOf(map.get("total_plan").toString());
        }
        // 4. 查询本周， 已经学习的总计划数量
        LocalDate now = LocalDate.now();
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(now);
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(now);
        Integer weekFinishPlanNum = recordMapper.selectCount(Wrappers.<LearningRecord>lambdaQuery()
                .eq(LearningRecord::getUserId, user)
                .eq(LearningRecord::getFinished, true)
                .between(LearningRecord::getFinishTime, weekBeginTime, weekEndTime));
        // 5. 查询课表数据
        Page<LearningLesson> page = this.lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .in(LearningLesson::getStatus, LessonStatus.LEARNING, LessonStatus.NOT_BEGIN)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if(CollUtils.isEmpty(records)){
            LearningPlanPageVO vo = new LearningPlanPageVO();
            vo.setTotal(0L);
            vo.setPages(0L);
            vo.setList(CollUtils.emptyList());
            return vo;
        }
        // 6. 远程调用课程服务 获取课程信息
        List<Long> courceIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> cinfos = courseClient.getSimpleInfoList(courceIds);
        if(CollUtils.isEmpty(cinfos)){
            throw new BizIllegalException("课程不存在");
        }
        // 将课程信息转换为map方便查询
        Map<Long, CourseSimpleInfoDTO> cinfosMap = cinfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        // 7. 查询学习记录表对本周当前用户下，每一门课下以学习小节数据
        QueryWrapper<LearningRecord> rwrapper = new QueryWrapper<>();
        rwrapper.select("lesson_id", "count(*) as userId");
        rwrapper.eq("user_id", user);
        rwrapper.eq("finished", true);
        rwrapper.between("finish_time", weekBeginTime, weekEndTime);
        rwrapper.groupBy("lesson_id");
        List<LearningRecord> learningRecords = recordMapper.selectList(rwrapper);
        if(CollUtils.isEmpty(learningRecords)){
            LearningPlanPageVO vo = new LearningPlanPageVO();
            vo.setTotal(0L);
            vo.setList(CollUtils.emptyList());
            vo.setPages(0L);
            return vo;
        }
        // 本周完成小节数量
        Map<Long, Long> weekFinishNumMap = learningRecords.stream().collect(Collectors.toMap(LearningRecord::getLessonId, LearningRecord::getUserId));

        // 8. 封装
        LearningPlanPageVO learningPlanPageVO = new LearningPlanPageVO();
        learningPlanPageVO.setWeekTotalPlan(totolPlan);
        learningPlanPageVO.setWeekFinished(weekFinishPlanNum);
        List<LearningPlanVO> voList = new ArrayList<>();
        for(LearningLesson record: records){
            LearningPlanVO learningPlanVO = BeanUtils.copyBean(record, LearningPlanVO.class);
            CourseSimpleInfoDTO infoDTO = cinfosMap.get(record.getCourseId());
            if(infoDTO != null){
                learningPlanVO.setCourseName(infoDTO.getName());
                learningPlanVO.setSections(infoDTO.getSectionNum());
            }
            learningPlanVO.setWeekLearnedSections(weekFinishNumMap.getOrDefault(record.getId(), 0L).intValue());
            voList.add(learningPlanVO);
        }
        learningPlanPageVO.setTotal(page.getTotal());
        learningPlanPageVO.setPages(page.getPages());
        learningPlanPageVO.setList(voList);

        return learningPlanPageVO;
    }

    @Override
    public void deleteLession(Long userId, List<Long> courseIds) {
        // 1. 删除
        remove(Wrappers.<LearningLesson>lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getCourseId, courseIds));
    }


}
